import { DynamicModule, Logger, Module } from "@nestjs/common";
import glob from "glob";
import { chain } from "lodash";

export interface AutoProviderModuleOptions {
  name?: string;
  global?: boolean;
  path: string[];
}

@Module({})
export class AutoProviderModule {
  static forRoot(data: AutoProviderModuleOptions): DynamicModule {
    console.log(
      "%c [ providers ]-15",
      "font-size:13px; background:pink; color:#bf2c9f;",
      chain(data.path)
    );
    const providers: any[] = chain(data.path)
      // 在每一个指定的路径下寻找所有符合条件的文件
      .map((i) => glob.sync(i))
      .flatten()
      // 尝试导入 js 模块
      .map((path) => require(path))
      .map((i: any): any[] => {
        return Object.values(i) as any[];
      })
      .flatten()
      // 对于 Nest.js Provider
      // 导入的值首先得是 class 函数类型（ class Test {}, typeof Test === 'function'）
      // class 有 @Injectable 装饰器，具体体现为 Reflect.getOwnMetadataKeys 有 '__injectable__'
      .filter(
        (i) =>
          typeof i === "function" &&
          Reflect.getOwnMetadataKeys(i).includes("__injectable__")
      )
      .value();

    // 日志输出有哪些 Provider 被自动识别并导入
    if (providers.length > 0) {
      Logger.log(
        `${data.name ? `[${data.name}] ` : ""}Auto loaded: ${providers
          .map((i) => i.name)
          .join(", ")}`,
        this.name
      );
    } else {
      Logger.warn(
        `${data.name ? `[${data.name}] ` : ""}No providers found`,
        this.name
      );
    }

    // 创建动态模块
    return {
      module: AutoProviderModule,
      global: data.global,
      providers: [...providers],
      exports: [...providers],
    };
  }
}
